---
id: versioning
title: Versioning - .NET SDK
sidebar_label: Versioning
description: Learn how to use the .NET SDK Patching API to safely deploy new code versions, handle deprecated patches, and manage Workflow activities using Temporal for long-running tasks.
toc_max_heading_level: 4
keywords:
  - best practices
  - code sample
  - deployment
  - deployment safety
  - deprecated patches
  - how-to
  - patching
  - dotnet
  - dotnet sdk
  - version
  - versioning
  - workflow completion
  - workflow history
  - workflow transition
tags:
  - Workflows
  - .Net SDK
  - Temporal SDKs
  - Versioning
  - Patching
---

This page shows how to do the following:

- [Use the .NET SDK Patching API](#dotnet-sdk-patching-api)
- [Patching in new code](#using-patched-for-workflow-history-markers)
- [Understanding deprecated Patches in the .NET SDK](#deprecated-patches)
- [Safe Deployment of PostPatchActivity](#deploy-postpatchactivity)

## Introduction to Versioning

Because we design for potentially long running Workflows at scale, versioning with Temporal works differently. We explain more in this optional 30 minute introduction:

<div style={{ position: "relative", paddingBottom: "56.25%", height: 0 }}>
  <iframe
    src="https://www.youtube.com/embed/kkP899WxgzY?autoplay=0"
    style={{ position: "absolute", top: 0, left: 0, width: "100%", height: "100%" }}
    frameborder="0"
    allow="accelerometer; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
    allowfullscreen>
  </iframe>
</div>

## Use the .NET SDK Patching API {#dotnet-sdk-patching-api}

**How to use the .NET SDK Patching API using the Temporal .NET SDK**

In principle, the .NET SDK's patching mechanism operates similarly to other SDKs in a "feature-flag" fashion. However, the "versioning" API now uses the concept of "patching in" code.

To understand this, you can break it down into three steps, which reflect three stages of migration:

- Running `PrePatchActivity` code while concurrently patching in `PostPatchActivity`.
- Running `PostPatchActivity` code with deprecation markers for `my-patch` patches.
- Running only the `PostPatchActivity` code.

Let's walk through this process in sequence.

Suppose you have an initial Workflow version called `PrePatchActivity`:

```csharp
[Workflow]
public class MyWorkflow
{
    [WorkflowRun]
    public async Task RunAsync()
    {
        this.result = await Workflow.ExecuteActivityAsync(
            (MyActivities a) => a.PrePatchActivity(),
            new() { StartToCloseTimeout = TimeSpan.FromMinutes(5) });

        // ...
    }
}
```

Now, you want to update your code to run `PostPatchActivity` instead. This represents your desired end state.

```csharp
[Workflow]
public class MyWorkflow
{
    [WorkflowRun]
    public async Task RunAsync()
    {
        this.result = await Workflow.ExecuteActivityAsync(
            (MyActivities a) => a.PostPatchActivity(),
            new() { StartToCloseTimeout = TimeSpan.FromMinutes(5) });

        // ...
    }
}
```

**Problem: You cannot deploy `PostPatchActivity` directly until you're certain there are no more running Workflows created using the `PrePatchActivity` code, otherwise you are likely to cause a nondeterminism error.**

Instead, you'll need to deploy `PostPatchActivity` and use the [Patched](https://dotnet.temporal.io/api/Temporalio.Workflows.Workflow.html#Temporalio_Workflows_Workflow_Patched_System_String_) method to determine which version of the code to execute.

Implementing patching involves three steps:

1. Use [Patched](https://dotnet.temporal.io/api/Temporalio.Workflows.Workflow.html#Temporalio_Workflows_Workflow_Patched_System_String_) to patch in new code and run it alongside the old code.
2. Remove the old code and apply [DeprecatePatch](https://dotnet.temporal.io/api/Temporalio.Workflows.Workflow.html#Temporalio_Workflows_Workflow_DeprecatePatch_System_String_).
3. Once you're confident that all old Workflows have finished executing, remove `DeprecatePatch`.

### Patching in new code {#using-patched-for-workflow-history-markers}

Using `Patched` inserts a marker into the Workflow History.

During replay, if a Worker encounters a history with that marker, it will fail the Workflow task when the Workflow code doesn't produce the same patch marker (in this case, `my-patch`). This ensures you can safely deploy code from `PostPatchActivity` as a "feature flag" alongside the original version (`PrePatchActivity`).

```csharp
[Workflow]
public class MyWorkflow
{
    [WorkflowRun]
    public async Task RunAsync()
    {
        if (Workflow.Patched("my-patch"))
        {
            this.result = await Workflow.ExecuteActivityAsync(
                (MyActivities a) => a.PostPatchActivity(),
                new() { StartToCloseTimeout = TimeSpan.FromMinutes(5) });
        }
        else
        {
            this.result = await Workflow.ExecuteActivityAsync(
                (MyActivities a) => a.PrePatchActivity(),
                new() { StartToCloseTimeout = TimeSpan.FromMinutes(5) });
        }

        // ...
    }
}
```

### Understanding deprecated Patches in the .NET SDK {#deprecated-patches}

After ensuring that all Workflows started with `PrePatchActivity` code have finished, you can [deprecate the patch](https://dotnet.temporal.io/api/Temporalio.Workflows.Workflow.html#Temporalio_Workflows_Workflow_DeprecatePatch_System_String_).

Deprecated patches serve as a bridge between `PrePatchActivity` and `PostPatchActivity`. They function similarly to regular patches by adding a marker to the Workflow History. However, this marker won't cause a replay failure when the Workflow code doesn't produce it.

If, during the deployment of `PostPatchActivity`, there are still live Workers running `PrePatchActivity` code and these Workers pick up Workflow histories generated by `PostPatchActivity`, they will safely use the patched branch.

```csharp
[Workflow]
public class MyWorkflow
{
    [WorkflowRun]
    public async Task RunAsync()
    {
        Workflow.DeprecatePatch("my-patch")
        this.result = await Workflow.ExecuteActivityAsync(
            (MyActivities a) => a.PostPatchActivity(),
            new() { StartToCloseTimeout = TimeSpan.FromMinutes(5) });

        // ...
    }
}
```

### Safe Deployment of PostPatchActivity {#deploy-postpatchactivity}

You can safely deploy `PostPatchActivity` once all Workflows labeled my-patch or earlier are finished, based on the previously mentioned assertion.

```csharp
[Workflow]
public class MyWorkflow
{
    [WorkflowRun]
    public async Task RunAsync()
    {
        this.result = await Workflow.ExecuteActivityAsync(
            (MyActivities a) => a.PostPatchActivity(),
            new() { StartToCloseTimeout = TimeSpan.FromMinutes(5) });

        // ...
    }
}
```
